package service_sys

import (
	"context"
	"fmt"
	"go_web/internal/model"
	"go_web/internal/model/model_sys"
	"go_web/internal/repo/repo_sys"
	"go_web/internal/req/req_sys"
	"go_web/internal/res/res_sys"
	"go_web/pkg/req"
	"go_web/pkg/res"
	"go_web/pkg/utils"
	"math"
	"time"

	"github.com/fatih/structs"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/copier"
	"gorm.io/gen"
	"gorm.io/gen/field"
)

type SysUserService struct{}

// 创建新的 SysUserService
func NewSysUserService() *SysUserService {
	return &SysUserService{}
}

// 分页查询
func (*SysUserService) Page(c context.Context, pageReq req_sys.SysUserPageReq) (*res.PageRes, error) {
	offset := (pageReq.Page - 1) * pageReq.PageSize
	q := repo_sys.SysUser.WithContext(c)

	// 排序处理
	if pageReq.SortField != nil {
		sortField := utils.ConvertToSnakeCase(*pageReq.SortField)
		orderFieldExpr := field.NewUnsafeFieldRaw(sortField)
		if pageReq.SortOrder != nil {
			if *pageReq.SortOrder == "asc" {
				q = q.Order(orderFieldExpr.Asc())
			} else {
				q = q.Order(orderFieldExpr.Desc())
			}
		} else {
			q = q.Order(orderFieldExpr.Asc())
		}
	}

	// 执行分页查询
	list, count, err := q.FindByPage(offset, pageReq.PageSize)
	if err != nil {
		return nil, err
	}

	// 计算总页数
	page := res.PageRes{
		List:     list,
		Total:    count,
		Page:     pageReq.Page,
		PageSize: pageReq.PageSize,
		Pages:    int64(math.Ceil(float64(count) / float64(pageReq.PageSize))),
	}

	return &page, nil
}

// 添加 SysUser
func (*SysUserService) Add(c context.Context, addReq req_sys.SysUserAddReq) (int64, error) {
	var sysUser model_sys.SysUser
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := tx.SysUser.WithContext(c)
		pwdByAes, err := utils.AesEncrypt(addReq.Password, "16bytekey1234567")
		if err != nil {
			return err
		}
		addReq.Password = pwdByAes
		err = copier.Copy(&sysUser, &addReq)
		if err != nil {
			return err
		}
		err = q.Create(&sysUser)
		if err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		return 0, err
	}

	return sysUser.ID, nil
}

// 编辑 SysUser 已开启事务
func (*SysUserService) Edit(c context.Context, editReq req_sys.SysUserEditReq) (int64, error) {
	var result gen.ResultInfo
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := tx.SysUser.WithContext(c).Where(repo_sys.SysUser.ID.Eq(editReq.ID))
		SysUser, err := q.First()
		if err != nil {
			return err
		}
		err = copier.Copy(&SysUser, &editReq)
		if err != nil {
			return err
		}
		result, err = q.Updates(structs.Map(SysUser))
		if err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		if utils.IsOptimisticLockError(err) {
			return -1, nil // 乐观锁报错（版本不一致）
		}
		return 0, err
	}
	return result.RowsAffected, nil
}

// 删除 SysUser 已开启事务
func (*SysUserService) Delete(c context.Context, idsReq req.IdsReq) (int64, error) {
	var result gen.ResultInfo
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := repo_sys.SysUser.WithContext(c)
		ids, err := idsReq.ToInt64Slice()
		if err != nil {
			return err
		}
		sysUserList, err := q.Where(repo_sys.SysUser.ID.In(ids...)).Find()
		if err != nil {
			return err
		}
		result, err = q.Delete(sysUserList...)
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return 0, err
	}
	return result.RowsAffected, nil
}

// 查看 SysUser 详情
func (*SysUserService) Detail(c context.Context, userId int64) (*model_sys.SysUser, error) {
	q := repo_sys.SysUser.WithContext(c)
	SysUser, err := q.Where(repo_sys.SysUser.ID.Eq(userId)).First()
	if err != nil {
		return nil, err
	}
	return SysUser, nil
}

// 用户名登录
func (*SysUserService) Login(c context.Context, loginReq req_sys.SysLoginReq) (*model.Token, *int64, error) {
	q := repo_sys.SysUser.WithContext(c)
	SysUser, err := q.Where(repo_sys.SysUser.Username.Eq(loginReq.Username)).First()
	if err != nil {
		return nil, nil, err
	}
	pwdByAes, err := utils.AesEncrypt(loginReq.Password, "16bytekey1234567")
	if err != nil {
		return nil, nil, err
	}
	if pwdByAes != SysUser.Password {
		return nil, nil, fmt.Errorf("密码不正确")
	}
	token, err := utils.GenerateToken(SysUser.ID)
	if err != nil {
		return nil, nil, err
	}
	err = utils.LoginAtRedis(c, token.AccessToken, SysUser.ID, time.Duration(token.Expire)*time.Second)
	if err != nil {
		return nil, nil, err
	}
	return &token, &SysUser.ID, nil
}

func (*SysUserService) RefreshToken(c context.Context) (*model.Token, *int64, error) {
	refreshToken, err := utils.GetRefreshTokenFromHeader(c.(*gin.Context))
	if err != nil {
		return nil, nil, err
	}
	claims, err := utils.ValidateRefreshToken(*refreshToken)
	if err != nil {
		return nil, nil, err
	}
	ret, err := utils.GenerateToken(claims.UserId)
	if err != nil {
		return nil, nil, err
	}
	return &ret, &claims.UserId, nil
}

func (*SysUserService) GetUserInfo(c context.Context) (*res_sys.SysUserRes, error) {
	token, err := utils.GetTokenFromHeader(c.(*gin.Context))
	if err != nil {
		return nil, err
	}
	userId, err := utils.GetUserIdFromToken(*token)
	if err != nil {
		return nil, err
	}
	q := repo_sys.SysUser.WithContext(c)
	SysUser, err := q.Where(repo_sys.SysUser.ID.Eq(userId)).First()
	if err != nil {
		return nil, err
	}
	var ret *res_sys.SysUserRes = &res_sys.SysUserRes{}
	err = copier.Copy(ret, SysUser)
	if err != nil {
		return nil, err
	}
	bindList, err := repo_sys.SysUserBind.FindUserInfoBindResList(userId)
	if err != nil {
		return nil, err
	}

	ret.BindInfoList = bindList
	return ret, nil
}
